package org.iabako.server.serviceimpl.security;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.log4j.Logger;
import org.iabako.server.conf.AppConf;
import org.iabako.server.dao.user.UserDAO;
import org.iabako.server.dao.user.UserPayPalTokenDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.user.Enterprise;
import org.iabako.shared.entity.user.User;
import org.iabako.shared.entity.user.UserPayPalToken;
import org.iabako.shared.iservice.user.UserService;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;

/**
 * Created by jose on 24/09/14.
 */

@Service("springUserDetailsService")
public class SpringUserDetailsServiceImpl implements SpringUserDetailsService {

    static Logger log = Logger.getLogger(SpringUserDetailsServiceImpl.class.getName());

    @Autowired
    UserDAO userDAO;
    @Autowired
    UserPayPalTokenDAO userPayPalTokenDAO;
    @Autowired
    private AppConf appConf;
    @Autowired
    UserService userService;
    @Autowired
    SessionUser sessionUser;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userService.getUserByEmail(username);

        if (user == null) {
            return new SpringUserDetailsImpl();
        }

        try {
            //This should not be blocking
            verifyNotIntegratedPayments(user.getEnterprise());

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        SpringUserDetailsImpl ud = new SpringUserDetailsImpl();
        ud.setUsername(user.getEmail());
        ud.setPassword(user.getPassword());

        // WARNING: Spring-Security authentication hasn't been done yet !
        // Don't do anything insecure here

        return ud;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void verifyNotIntegratedPayments(Enterprise enterprise) throws URISyntaxException, IOException {

        List<UserPayPalToken> tokens = userPayPalTokenDAO.getNotPayedUserPayPalTokenByEmail(enterprise);

        if (tokens == null || tokens.isEmpty()) {
            return;
        }

        for (UserPayPalToken token : tokens) {
            log.info("Verification of not integrated payments...");

            HttpClient client = HttpClientBuilder.create().build();

            Date initDate = new ServerTools().addMonthsToDate(new Date(), -12);
            String initDateYYYYMMDD = GenericTools.formatDateyyyyMMdd(initDate);

            URIBuilder builder = new URIBuilder(appConf.getPayPalAPIUrl())
                    .addParameter("USER", appConf.getPayPalAPIUser())
                    .addParameter("PWD", appConf.getPayPalAPIPassword())
                    .addParameter("SIGNATURE", appConf.getPayPalAPISignature())
                    .addParameter("METHOD", appConf.getPayPalAPITransactionMethod())
                    .addParameter("VERSION", appConf.getPayPalAPIVersion())
                    .addParameter("INVNUM", token.getTransactionId())
                    .addParameter("STARTDATE", initDateYYYYMMDD + "T00:00:00Z");

            /*Test example

            URIBuilder builder = new URIBuilder("https://api-3t.sandbox.paypal.com/nvp")
                    .addParameter("USER", "iabakoproject-facilitator_api1.gmail.com")
                    .addParameter("PWD", "8Z2B6EPNY7TXNF6Z")
                    .addParameter("SIGNATURE", "ArzLbDkEAt8X0WpsQfXHZNFHGeJDAJYpgvPKnLwZhBq0VM5s062WuicY")
                    .addParameter("METHOD", "TransactionSearch")
                    .addParameter("VERSION", "95.0")
                    .addParameter("INVNUM", token.getTransactionId())
                    .addParameter("STARTDATE", "2014-12-01T00:00:00Z");*/


            HttpGet get = new HttpGet(builder.build());

            log.info("Calling PayPal service...");
            HttpResponse postResponse = client.execute(get);

            BufferedReader rd = new BufferedReader(
                    new InputStreamReader(postResponse.getEntity().getContent()));

            StringBuilder result = new StringBuilder();
            String line = "";

            while ((line = rd.readLine()) != null) {
                result.append(line);
            }

            String payPalResponse = URLDecoder.decode(result.toString(), "UTF-8").replace("&L_", "\n");

            if (!payPalResponse.contains("ACK=Success")) {
                log.error("PayPal acknowledge ERROR !");
                log.error(payPalResponse);
                userService.setUserPayPalTokenCanceled(token.getTransactionId(), payPalResponse);

            } else if (payPalResponse.contains("EMAIL0=")
                    && payPalResponse.contains("STATUS0=")) {

                String payerEmail = payPalResponse.substring(payPalResponse.indexOf("EMAIL0=") + "EMAIL0=".length());
                payerEmail = payerEmail.substring(0, payerEmail.indexOf("\n"));

                String status = payPalResponse.substring(payPalResponse.indexOf("STATUS0=") + "STATUS0=".length());
                status = status.substring(0, status.indexOf("\n"));

                if (status.trim().equalsIgnoreCase("Completed")) {
                    userService.setUserPayPalTokenPayed(token.getTransactionId(), payerEmail, payPalResponse);

                } else {
                    userService.setUserPayPalTokenToVerify(token.getTransactionId(), payPalResponse);

                }
            } else {
                userService.setUserPayPalTokenCanceled(token.getTransactionId(), payPalResponse);
            }
        }
    }
}
